import json
import re
import logging
import uuid
from decimal import Decimal

from django.contrib.auth.mixins import LoginRequiredMixin

from apps.goods.models import SKU
from apps.orders.models import OrderInfo
from utils.view import LoginRequiredJsonMixin
from django.contrib.auth import login, logout, authenticate
from django.http import JsonResponse, HttpResponseBadRequest, HttpResponse
from django.shortcuts import render
from django.views import View
from django_redis import get_redis_connection

from apps.users.models import User, Address, Userwallet

logger = logging.getLogger('mall.log')


class RegisterView(View):
    def post(self, request):
        # vue前后端接收数据
        json_bytes = request.body  # 从请求体中获取原始的JSON数据，bytes类型的
        json_str = json_bytes.decode()  # 将bytes类型的JSON数据，转成JSON字符串
        json_dict = json.loads(json_str)  # 将JSON字符串，转成python的标准字典
        # 后端校验
        username = json_dict.get("username")
        password = json_dict.get("password")
        password2 = json_dict.get("password2")
        mobile = json_dict.get("mobile")
        allow = json_dict.get("allow")
        image_code = json_dict.get("image_code")
        # sms_code = json_dict.get("sms_code")
        email = json_dict.get("email")
        uuid = json_dict.get('uuid')
        # print(allow,username,image_code)
        if not all([username, password, password2, mobile, allow, uuid]):
            return JsonResponse({'code': 400, 'error': '参数不全'})
        if not re.match(r"^[a-zA-Z0-9_-]{5,20}$", username):
            return JsonResponse({'code': 400, 'error': '用户名格式不对'})
        if not re.match(r"^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$", email):
            return JsonResponse({'code': 400, 'error': '邮箱格式不对'})
        if password != password2:
            return JsonResponse({'code': 400, 'error': '两次密码不一致'})
        if not re.match(r"^1[3-9]\d{9}$", mobile):
            return JsonResponse({'code': 400, 'error': '手机号格式不对'})
        if allow != True:
            return JsonResponse({'code': 400, 'error': '没有构选协议'})
        if not re.match(r'^[0-9a-zA-Z]{8,20}$', password):
            return JsonResponse({'code': 400, 'error': '密码长度、格式不正确。长度8-20，必须数字字母'})
        if password != password2:
            return JsonResponse({'code': 400, 'error': '两次输入密码不一样'})

        redis_conn = get_redis_connection('default')
        img_code_redis = redis_conn.get('img:%s' % uuid)
        # if sms_code_redis is None:
        #     return JsonResponse({'code': 400, 'error': '短信验证码过期'})
        image_code_server = img_code_redis.decode()
        if image_code_server.lower() != image_code.lower():
            return JsonResponse({'code': 400, 'error': '验证码错误'})
        try:
            redis_conn.delete('img:%s' % uuid)
        except Exception as e:
            logger.error(e)
        # #没有问题实现注册
        # User.objects.create_user(username=username,password=password,mobile=mobile)

        try:
            # user = User.objects.create(username=username,password=encrypt.md5(password),mobile=mobile)
            user = User.objects.create_user(username=username, password=password, mobile=mobile, email=email)
            new_wallet = Userwallet(user=user, wallet_income=0)  # 注册成功创建此用户的账户表，默认资产为0
            new_wallet.save()
        except Exception as e:
            logger.info(e)
            return JsonResponse({'code': 400, 'errmsg': '注册失败!'})
        # # 如何设置session信息
        # request.session['user_id']=user.id
        # login(request, user) #该⽅法会将当前已登录的⽤户写⼊session中，并将 sessionid写⼊cookie发送给浏览器
        # # 状态保持 -- 登录⽤户的状态保持
        # # user 已经登录的⽤户信息
        login(request, user)
        return JsonResponse({'code': 200, 'errmsg': '注册成功'})


class UsernameView(View):
    """用户名重复"""

    def get(self, request, username):
        count = User.objects.filter(username=username).count()
        return JsonResponse({'code': 0, 'errmsg': 'ok', 'count': count})


class mobileView(View):
    """手机号重复"""

    def get(self, request, mobile):
        count = User.objects.filter(mobile=mobile).count()
        return JsonResponse({'code': 0, 'errmsg': 'ok', 'count': count})


class emailView(View):
    """邮箱重复"""

    def get(self, request, email):
        count = User.objects.filter(email=email).count()
        return JsonResponse({'code': 0, 'errmsg': 'ok', 'count': count})


class LoginView(View):
    def post(self, request):
        # vue前后端接收数据
        #         # try:
        json_bytes = request.body  # 从请求体中获取原始的JSON数据，bytes类型的
        json_str = json_bytes.decode()  # 将bytes类型的JSON数据，转成JSON字符串
        json_dict = json.loads(json_str)  # 将JSON字符串，转成python的标准字典
        # 后端校验
        username = json_dict.get("username")
        password = json_dict.get("password")
        remembered = json_dict.get("remembered")
        # print(username, password)
        # 校验参数
        if not all([username, password]):
            return JsonResponse({'code': 400, 'error': '参数不全'})

        if re.match('^1[3-9]\d{9}$', username):
            User.USERNAME_FIELD = 'mobile'
        else:
            User.USERNAME_FIELD = 'username'
        if not re.match(r"^[a-zA-Z0-9_-]{5,20}$", username):
            return JsonResponse({'code': 400, 'error': '请输入正确格式的手机号或用户名'})
        if not re.match(r'^[0-9a-zA-Z]{5,20}$', password):
            return JsonResponse({'code': 400, 'error': '密码长度、格式不正确。长度5-20，必须数字字母'})
        user = authenticate(username=username, password=password)

        if user is None:
            return JsonResponse({'code': 400, 'error': '账号或者密码错误'})
        if not remembered:
            # 没有记住登陆：状态保持在浏览器会话结束后就销毁
            request.session.set_expiry(0)  # 单位秒
        else:
            # 记住登陆：状态保持两周：默认是两周
            request.session.set_expiry(None)
        # except Exception as e:
        #     logger.error(e)
        login(request, user)
        response = JsonResponse({'code': 200, 'error': '登陆成功'})
        u = json.dumps(user.nick_name)  # 用户名序列化
        # print(user.nick_name)
        response.set_cookie("username", u)  # 用户名写入cookie
        return response


class LogoutView(View):
    def delete(self, request):
        logout(request)  # 退出⽤户，本质就是删除了sessionid
        resp = JsonResponse({'code': 200, 'error': '退出登录'})
        # 为什么这⾥需要删除该cookie，因为前端是需要根据这个cookie的值来判断和显示登录⽤ 户信息
        resp.delete_cookie('username')  # 清除cookie信息
        return resp


# 判断用户是否登陆
class UserInfoView(LoginRequiredJsonMixin, View):
    def get(self, request):
        wallet_incomes = Userwallet.objects.filter(user=request.user).first()
        context = {
            'username': request.user.username,
            'mobile': request.user.mobile,
            'email': request.user.email,
            'nick_name': request.user.nick_name,
            'wallet_income': wallet_incomes.wallet_income
            # 'email_active': request.user.email_active,
        }
        return JsonResponse({'code': 200, 'error': 'ok', 'context': context})


# 修改昵称
class Nickname(LoginRequiredJsonMixin, View):
    def put(self, request):
        json_bytes = request.body  # 从请求体中获取原始的JSON数据，bytes类型的
        json_str = json_bytes.decode()  # 将bytes类型的JSON数据，转成JSON字符串
        json_dict = json.loads(json_str)  # 将JSON字符串，转成python的标准字典
        # 后端校验
        nickname = json_dict.get("nick_name")
        if nickname:
            try:
                request.user.nick_name = nickname
                request.user.save()
                return JsonResponse({"code": 200, "error": "ok", })
            except Exception as e:
                logger.error(e)
                return JsonResponse({"code": 400, "error": "修改失败联系管理员", })
        return JsonResponse({"code": 400, 'error': '请输入修改信息'})


# 用户新增、查看地址
class CreateAddressView(LoginRequiredJsonMixin, View):
    """查看地址"""

    def get(self, request):
        """获取当前用户下的所有地址信息"""
        # 1.查询指定数据
        user = request.user
        # addresses=user.addresses # 该方法也可以查询出当前用户下的所有地址信息

        addresses = Address.objects.filter(user=user, is_deleted=False)  # 获取当前用户下的所有没有被删除（逻辑）的所有地址信息
        # 2.将对象数据转换为字典数据
        address_list = []
        for address in addresses:
            address_list.append({
                "id": address.id,
                "title": address.title,
                "receiver": address.receiver,
                "province": address.province.name,
                "city": address.city.name,
                "district": address.district.name,
                "place": address.place,
                "mobile": address.mobile,
                "tel": address.tel,
                "email": address.email,

            })

        # 3.返回响应
        district = request.user.default_address_id

        return JsonResponse({'code': 0, 'errmsg': 'ok', 'addresses': address_list, 'district': district})

    """新增地址"""

    def post(self, request):
        """实现新增地址逻辑"""
        # 判断是否超过地址上限：最多20个
        # Address.objects.filter(user=request.user).count()
        count = request.user.addresses.count()
        if count >= 20:
            return JsonResponse({'code': 400, 'errmsg': '超过地址数量上限'})

        # 接收参数
        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        # 校验参数
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return HttpResponseBadRequest('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return HttpResponseBadRequest('参数mobile有误')
        if tel:
            if not re.match(r"^1[3-9]\d{9}$", tel):
                return HttpResponseBadRequest('参数tel有误')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return HttpResponseBadRequest('参数email有误')

        # 保存地址信息
        try:
            address = Address.objects.create(
                user=request.user,
                title=receiver,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email
            )

            # 设置默认地址
            if not request.user.default_address:
                request.user.default_address = address
                request.user.save()
        except Exception as e:
            logger.error(e)
            return JsonResponse({'code': 400, 'errmsg': '新增地址失败'})

        # 新增地址成功，将新增的地址响应给前端实现局部刷新
        address_dict = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }

        # 响应保存结果
        return JsonResponse({'code': 0, 'errmsg': '新增地址成功', 'address': address_dict})

    """修改地址"""

    def put(self, request, address_id):
        """修改和删除地址"""
        # 1、接收参数
        json_dict = json.loads(request.body.decode())  # 获取前端提交来的json数据
        receiver = json_dict.get('receiver')  # 获取收件人
        province_id = json_dict.get('province_id')  # 获取省份id
        city_id = json_dict.get('city_id')  # 获取城市id
        district_id = json_dict.get('district_id')  # 获取地址id
        place = json_dict.get('place')  # 获取地址信息
        mobile = json_dict.get('mobile')  # 获取手机号信息
        tel = json_dict.get('tel')  # 获取固定电话信息
        email = json_dict.get('email')  # 获取邮箱信息

        # 2、校验参数
        # 2-1、参数不全判断
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return JsonResponse({'code': 400, 'errmsg': '缺少必传参数'})
        # 2-2、手机号码判断
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400, 'errmsg': '参数手机号码格式有误'})
        # 2-3、固定号码有的时候需要判断
        if tel:
            if not re.match(r'^1[3-9]\d{9}$', mobile):
                return JsonResponse({'code': 400, 'errmsg': '参数固定电话格式有误'})
        # 2-4、邮箱有的时候需要判断
        if email:
            if not re.match(r'^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$', email):
                return JsonResponse({'code': 400, 'errmsg': '参数email有误'})

        # 3、判断地址是否存在,并更新地址信息
        try:
            Address.objects.filter(id=address_id).update(
                user=request.user,
                title=receiver,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email
            )
        except Exception as e:
            logger.error(e)
            return JsonResponse({'code': 400, 'errmsg': '更新地址失败'})

        # 4、构造响应数据
        address = Address.objects.get(id=address_id)
        address_dict = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "province_id": address.province_id,
            "city": address.city.name,
            "city_id": address.city_id,
            "district": address.district.name,
            "district_id": address.district_id,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }

        # 响应更新地址结果
        return JsonResponse({'code': 0, 'errmsg': '更新地址成功', 'address': address_dict})

    def delete(self, request, address_id):
        """删除地址"""
        try:
            # 1、查询要删除的地址
            address = Address.objects.get(id=address_id)

            # 2、将地址逻辑删除设置为True
            address.is_deleted = True
            address.save()
        except Exception as e:
            logger.error(e)
            return JsonResponse({'code': 400, 'errmsg': '删除地址失败'})

        # 响应删除地址结果
        return JsonResponse({'code': 0, 'errmsg': '删除地址成功'})


class ChangePasswordView(LoginRequiredJsonMixin, View):
    """修改密码"""

    def put(self, request):
        """实现修改密码逻辑"""
        # 接收参数
        dict = json.loads(request.body.decode())
        old_password = dict.get('old_pwd')
        new_password = dict.get('new_pwd')
        new_password2 = dict.get('new_cpwd')

        # 校验参数
        if not all([old_password, new_password, new_password2]):
            return JsonResponse({'code': 400,
                                 'errmsg': '缺少必传参数'})

        result = request.user.check_password(old_password)
        if not result:
            return JsonResponse({'code': 400,
                                 'errmsg': '原始密码不正确'})

        if not re.match(r'^[0-9A-Za-z]{8,20}$', new_password):
            return JsonResponse({'code': 400,
                                 'errmsg': '密码最少8位,最长20位'})

        if new_password != new_password2:
            return JsonResponse({'code': 400,
                                 'errmsg': '两次输入密码不一致'})

        # 修改密码
        try:
            request.user.set_password(new_password)
            request.user.save()
        except Exception as e:
            return JsonResponse({'code': 400,
                                 'errmsg': '修改密码失败'})

        # 清理状态保持信息
        logout(request)

        response = JsonResponse({'code': 0,
                                 'errmsg': 'ok'})

        response.delete_cookie('username')

        # # 响应密码修改结果：重定向到登录界面
        return response


class AddressDefaultView(LoginRequiredJsonMixin, View):
    """默认值"""

    def put(self, request, address_id):
        """设置默认地址"""
        try:
            # 接收参数,查询地址
            address = Address.objects.get(id=address_id)

            # 设置地址为默认地址
            request.user.default_address = address  # 设置当前用户的默认地址字段为查询到的当前地址信息
            request.user.save()
        except Exception as e:
            logger.error(e)
            return JsonResponse({'code': 400, 'errmsg': '设置默认地址失败'})

        # 响应设置默认地址结果
        return JsonResponse({'code': 0, 'errmsg': '设置默认地址成功'})


class UpdateTitleAddressView(LoginRequiredJsonMixin, View):
    """设置地址标题"""

    def put(self, request, address_id):
        """设置地址标题"""
        # 接收参数：地址标题
        json_dict = json.loads(request.body.decode())
        title = json_dict.get('title')

        try:
            # 查询地址
            address = Address.objects.get(id=address_id)

            # 设置新的地址标题
            address.title = title
            address.save()
        except Exception as e:
            logger.error(e)
            return JsonResponse({'code': 400, 'errmsg': '设置地址标题失败'})

        # 4.响应删除地址结果
        return JsonResponse({'code': 0, 'errmsg': '设置地址标题成功'})


class UserBrowseHistory(View):
    """用户浏览记录"""

    def get(self, request):
        """获取用户浏览记录"""
        # 获取Redis存储的sku_id列表信息
        redis_conn = get_redis_connection('history')
        sku_ids = redis_conn.lrange('history_%s' % request.user.id, 0, -1)

        # 根据sku_ids列表数据，查询出商品sku信息
        skus = []
        for sku_id in sku_ids:
            sku = SKU.objects.get(id=sku_id)
            skus.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price
            })

        return JsonResponse({'code': 0, 'errmsg': 'OK', 'skus': skus})

    def post(self, request):
        """保存用户浏览记录"""
        # 接收参数
        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get('sku_id')

        # 校验参数
        try:
            SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return JsonResponse({'code': 400, 'errmsg': 'sku不存在'})

        # 保存用户浏览数据
        redis_conn = get_redis_connection('history')
        pl = redis_conn.pipeline()
        user_id = request.user.id

        # 先去重
        pl.lrem('history_%s' % user_id, 0, sku_id)
        # 再存储
        pl.lpush('history_%s' % user_id, sku_id)
        # 最后截取
        pl.ltrim('history_%s' % user_id, 0, 4)
        # 执行管道
        pl.execute()

        # 响应结果
        return JsonResponse({'code': 0, 'errmsg': 'OK'})


class MyorderView(LoginRequiredJsonMixin, View):
    def get(self, request):
        user = request.user
        oders = OrderInfo.objects.filter(user=user, total_count__gt=0, status=5).order_by('-create_time')
        oder_list = []
        for i in oders:
            tmp = {}
            tmp['order_id'] = i.order_id
            tmp['create_time'] = i.create_time.strftime("%Y-%m-%d, %H:%M:%S")
            # 'user':i.user.nick_name,
            tmp['total_count'] = i.total_count
            tmp['total_amount'] = i.total_amount
            tmp['status'] = i.get_status_display()
            tmp['sku'] = []
            for j in i.skus.all():
                tmp['sku'].append({
                    'order': j.sku.name,
                    'price': j.price,
                    'count': j.count,
                    'img_url': str(j.sku.default_image.url)
                })
            oder_list.append(tmp)
        # print(oder_list)
        return JsonResponse({"code": 200, 'oder_list': oder_list})






